{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "50bb83f5-5228-49cf-a9a9-88c11aff2cf9",
   "metadata": {},
   "source": [
    "# Obtención de datos"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "902288c8-52ba-4501-865f-a635e3763b29",
   "metadata": {},
   "source": [
    "En este código "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f355f41-1c5f-4dab-a142-5ccfbd7fcd9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# paquetes\n",
    "import neurokit2 as nk # incluye herramientas de análisis y detección de ondas de ECG\n",
    "import pandas as pd # para trabajar con DataFrames\n",
    "import numpy as np # para manejar tipos de números\n",
    "import math # para operaciones especiales\n",
    "import statistics # para operaciones especiales\n",
    "import os # para acciones del sistema operativo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e29da77-66f8-4ab6-95ee-c39f8d5fb057",
   "metadata": {},
   "outputs": [],
   "source": [
    "# creamos una función que nos regrese la información principal de cada ECG\n",
    "def analiza(id_ecg, categoria, senal, sr=100):\n",
    "    # usamos un try-except para las señales conflictivas\n",
    "    try:\n",
    "        # primero analizamos la información\n",
    "        senal_limpia = nk.ecg_clean(senal, sampling_rate=sr, method='neurokit') # quitamos el ruido de la señal\n",
    "        aux_rc, picos_R = nk.ecg_peaks(senal_limpia, sampling_rate=sr) # ubicamos los picos de las ondas R\n",
    "        _, picos_otros = nk.ecg_delineate(senal_limpia, picos_R, sampling_rate=sr, method=\"peak\") # ubicamos los otros picos\n",
    "    \n",
    "        # segundo organizamos los valores\n",
    "        ritmo_cardiaco = nk.ecg_rate(aux_rc, sampling_rate=sr)\n",
    "        picos_R = picos_R['ECG_R_Peaks'] # pasamos el dato de cuando ocurre el pico a lista\n",
    "        picos_R = [senal_limpia[x] for x in picos_R if not math.isnan(x)] # vemos la altura del pico / quitamos NaN's\n",
    "        picos_R = [x.astype(float) for x in picos_R] # transformamos a float para evitar problemas con el formato\n",
    "        picos_T = picos_otros['ECG_T_Peaks']\n",
    "        picos_T = [senal_limpia[x] for x in picos_T if not math.isnan(x)]\n",
    "        picos_T = [x.astype(float) for x in picos_T]\n",
    "        picos_P = picos_otros['ECG_P_Peaks']\n",
    "        picos_P = [senal_limpia[x] for x in picos_P if not math.isnan(x)]\n",
    "        picos_P = [x.astype(float) for x in picos_P]\n",
    "    \n",
    "        # tercero sacamos los resultados\n",
    "        max_RC = max(ritmo_cardiaco)                # los valores RC están en latidos por minuto (lpm).\n",
    "        min_RC = min(ritmo_cardiaco)\n",
    "        media_RC = statistics.mean(ritmo_cardiaco)\n",
    "        sd_RC = statistics.stdev(ritmo_cardiaco)\n",
    "        max_P = max(picos_P)                        # los valores de aqui para abajo están en mV.\n",
    "        media_P = statistics.mean(picos_P)\n",
    "        min_P = min(picos_P)\n",
    "        sd_P = statistics.stdev(picos_P)\n",
    "        max_R = max(picos_R)\n",
    "        media_R = statistics.mean(picos_R)\n",
    "        min_R = min(picos_R)\n",
    "        sd_R = statistics.stdev(picos_R)\n",
    "        max_T = max(picos_T)\n",
    "        media_T = statistics.mean(picos_T)\n",
    "        min_T = min(picos_T)\n",
    "        sd_T = statistics.stdev(picos_T)\n",
    "\n",
    "        # cuarto ordenamos los resultados\n",
    "        res = [id_ecg, categoria, \n",
    "               min_RC, media_RC, max_RC, sd_RC, \n",
    "               min_P, media_P, max_P, sd_P,\n",
    "               min_R, media_R, max_R, sd_R, \n",
    "               min_T, media_T, max_T, sd_T]\n",
    "    except:\n",
    "        # en caso de no poder realizar el proceso, regresa una lista de NaN's\n",
    "        res = [None for x in range(16)]\n",
    "        res = [id_ecg, categoria] + res\n",
    "        \n",
    "    return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ae8304a-ffa1-4618-a1b5-7dd5ff98982c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# creamos una función que explore los archivos .csv de la carpeta con ECG\n",
    "# y nos regrese un resumen de cada ECG como un renglón de un Data Frame\n",
    "def explorar(direccion, tipo = \".csv\"):\n",
    "\n",
    "    # creamos el dataframe ya con los títulos\n",
    "    df = pd.DataFrame(columns = [\"id_ecg\", \"categoria\",\n",
    "                                 \"min_RC\", \"media_RC\", \"max_RC\", \"sd_RC\",\n",
    "                                 \"min_P\", \"media_P\", \"max_P\", \"sd_P\", \n",
    "                                 \"min_R\", \"media_R\", \"max_R\", \"sd_R\", \n",
    "                                 \"min_T\", \"media_T\", \"max_T\", \"sd_T\"])\n",
    "    i = 0 # para saber en que renglón vamos\n",
    "    for root, dirs, files in os.walk(direccion): # os.walk va a ingresar a cada carpeta de la dirección y regresar el nombre de los archivos dentro\n",
    "        for name in files: # para cada archivo...\n",
    "            if name.endswith(tipo): # si el archivo es .csv...\n",
    "                id_ecg = name[8:-4] # el nombre es 'patient_####.csv' entonces hacemos slicing para quitar \"patient_\" y \".csv\".\n",
    "                cat = root[13:] # el root es 'Datos_Leonel\\carpeta' y queremos solo la carpeta, hacemos slicing.\n",
    "                archivo = root + \"\\\\\" + name # la dirección del archivo se obtiene concatenando root y file_name\n",
    "                senales = pd.read_csv(archivo, index_col='Unnamed: 0') # las señales están guardadas en formato .csv \n",
    "                senal_II = senales.II # Queremos la señal DII\n",
    "                renglon = analiza(id_ecg=id_ecg, categoria = cat, senal=senal_II, sr=100) # aplicamos 'analiza' a DII\n",
    "                df.loc[i,:] = renglon # concatena el resultado de 'analiza' al final del df\n",
    "                i += 1 # contabilizamos el renglón\n",
    "    return df # retornamos el dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ce5c219d-a932-434b-b88a-baf942782884",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ejecutamos y guardamos el df para acceder a él más fácilmente\n",
    "# solo como seguridad, (para evitar repetir el proceso en vano)\n",
    "# agregamos una llave que debe ajustarse a True si se quiere volver a calcular el dataframe\n",
    "\n",
    "recalcular_df = False # llave\n",
    "\n",
    "if recalcular_df:\n",
    "    df1 = explorar(direccion='Datos_Leonel')\n",
    "    df2 = pd.read_csv('ptbxl_database.csv')\n",
    "    df1 = df1.astype({'id_ecg':float})\n",
    "    df1 = df1.merge(df2[['ecg_id','patient_id','age','sex','height','weight']],\n",
    "                      how='left', left_on='id_ecg',right_on='ecg_id',sort=True)\n",
    "    df1.drop(labels='ecg_id', axis = 1, inplace=True)\n",
    "    df1.to_csv('df_datos.csv')\n",
    "    print(\"datos analizados y guardados :)\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c5da9cb-d78e-4ff6-a43a-322b2ccd3387",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# ahora si, accedemos al df de datos para ver qué tiene:\n",
    "pd.set_option('display.max_columns', 100)\n",
    "df = pd.read_csv('df_datos.csv', index_col='Unnamed: 0')\n",
    "df.head(10)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
